#ifndef __VIEWERCAMERASCENENODE_H__
#define __VIEWERCAMERASCENENODE_H__

#include "../include/I3DCameraSceneNode.h"

class CViewerCameraSceneNode : public I3DCameraSceneNode
{
protected:
	vector3dvpos LookAt;
	vPos zNear;
	vPos zFar;
	vPos Angle;
	vPos Aspect;
	vector3dvpos VUp;
	matrix3dvpos ProjectionMatrix;

	bool EnableDebugMovementType1;
	bool EnableDebugMovementType2;
	bool EnableDebugMovementType3;

public:
	CViewerCameraSceneNode(vPos angle=90.0,vPos aspect=1.0,vector3dvpos lookat=vector3dvpos(0.0,0.0,0.0),
		vPos znear=0.0,vPos zfar=100.0,vector3dvpos vup=vector3dvpos(0.0,1.0,0.0),ISceneNodeBasicParamsDeclaration);

	virtual ~CViewerCameraSceneNode();

	virtual vPos GetZNear()						{	return zNear;						}
	virtual vPos GetZFar()						{	return zFar;						}
	virtual vector3dvpos &GetLookAt()			{	return LookAt;						}
	virtual vPos GetLookAtX()					{	return LookAt.X;					}
	virtual vPos GetLookAtY()					{	return LookAt.Y;					}
	virtual vPos GetLookAtZ()					{	return LookAt.Z;					}
	virtual void SetLookAt(vector3dvpos &newla)	{	LookAt = newla;						}
	virtual void SetLookAtX(vPos newlax)		{	LookAt.X = newlax;					}
	virtual void SetLookAtY(vPos newlay)		{	LookAt.Y = newlay;					}
	virtual void SetLookAtZ(vPos newlaz)		{	LookAt.Z = newlaz;					}
	virtual vPos GetAngle()						{	return Angle;						}
	virtual vector3dvpos &GetVUp()				{	return VUp;							}
	virtual void SetVUp(vector3dvpos &newvup)	{	VUp = newvup;						}
	virtual vPos GetAspect()					{	return Aspect;						}
	virtual void SetAspect(vPos newAspect)		{	Aspect = newAspect;					}

	virtual void ActivateDebugMovementType1()	{	EnableDebugMovementType1 = true;	}
	virtual void DeActivateDebugMovementType1()	{	EnableDebugMovementType1 = false;	}
	virtual void ActivateDebugMovementType2()	{	EnableDebugMovementType2 = true;	}
	virtual void DeActivateDebugMovementType2()	{	EnableDebugMovementType2 = false;	}
	virtual void ActivateDebugMovementType3()	{	EnableDebugMovementType3 = true;	}
	virtual void DeActivateDebugMovementType3()	{	EnableDebugMovementType3 = false;	}

	inline void CalculateProjection()
	{
		vPos deltaZ(zFar - zNear);
		vPos radians = (vPos)(Angle / 2 * DEGTORAD);
		vPos sine(sin(radians));

		if ((deltaZ == 0.0) || (sine == 0.0) || (Aspect == 0.0))
		{
			return;
		}

		vPos cotangent(cos(radians) / sine);

		ProjectionMatrix.m[0] = cotangent / Aspect;
		ProjectionMatrix.m[5] = cotangent;
		ProjectionMatrix.m[10] = -(zFar + zNear) / deltaZ;
		ProjectionMatrix.m[11] = -1;
		ProjectionMatrix.m[14] = -2 * zNear * zFar / deltaZ;
		ProjectionMatrix.m[15] = 0;
	}

	inline void CalculatePerspective()
	{
		vector3dvpos Dist(LookAt - Position);
		vector3dvpos side;
		vector3dvpos up2(VUp);

		Dist.Normalize();
		side.ProductoCruz(Dist,up2);
		side.Normalize();
		up2.ProductoCruz(side,Dist);

		RelativeTransformation.m[0] = side.X;
		RelativeTransformation.m[4] = side.Y;
		RelativeTransformation.m[8] = side.Z;

		RelativeTransformation.m[1] = up2.X;
		RelativeTransformation.m[5] = up2.Y;
		RelativeTransformation.m[9] = up2.Z;

		RelativeTransformation.m[2] = -Dist.X;
		RelativeTransformation.m[6] = -Dist.Y;
		RelativeTransformation.m[10] = -Dist.Z;

		RelativeTransformation.SetTranslation(Position*-1.0);
	}

	virtual matrix3dvpos &GetRelativeTransformation()
	{
		RelativeTransformation.MakeIdentity();
		CalculateProjection();
		CalculatePerspective();

		return RelativeTransformation;
	}

	virtual matrix3dvpos &GetProjectionMatrix()		{	return ProjectionMatrix;	}

	virtual void Render(IDrawableFaceManager *dfm);
	virtual void OnRender();
	virtual void UpdateNode()
	{

	}

};

#endif
